//
//  CubeDemoDrawer.cpp
//  demo
//
//  Created by vonchenchen on 2021/3/18.
//  Copyright © 2021 vonchenchen. All rights reserved.
//

#include "CubeDrawer.h"
#include "BaseModle.h"

CubeDrawer::CubeDrawer(){
    
    InitCubeColorTexture();
}

CubeDrawer::~CubeDrawer(){
}

void CubeDrawer::Init(int width, int height){
    
    renderer.Init(width, height);
    
    //生成一块纹理
    _texture_0.reset(new ToyTexture(32, 32));
    for(int i=0; i<32; i++){
        for(int j=0; j<32; j++){
            _texture_0->SetPixel(i, j, 0xffff0000);
        }
    }
    _texture_1.reset(new ToyTexture(32, 32));
    for(int i=0; i<32; i++){
        for(int j=0; j<32; j++){
            _texture_1->SetPixel(i, j, 0xff003f00);
        }
    }
    _texture_2.reset(new ToyTexture(32, 32));
    for(int i=0; i<32; i++){
        for(int j=0; j<32; j++){
            _texture_2->SetPixel(i, j, 0xffffffff);
        }
    }
    //_texture_rabbit.reset(new ToyTexture("../../material/haha.bmp"));
    
    //光源位置与强度
    _light_1 = Light{{10, 10, 10}, {500, 500, 500}};
    //环境光强度
    Vec<3, float> amb_light_intensity{ 10, 10, 10 };
    
    renderer.SetVertxShader([&](int index, ShaderContext &output)->Vec<4, float>{

        std::cout<<"vertexs:"<<std::endl;
        _shader_vertexAttrib[index].pos.Print();
        Vec<4, float> pos = TransformCoordinate(_mvp_mat, _shader_vertexAttrib[index].pos);
        
        //传入纹理坐标 插值后用于片元着色器纹理采样
        output.varying_vec2f[VARYING_TEXUV] = _shader_vertexAttrib[index].uv;
        //传入顶点坐标 插值后用于片元着色器计算光照点位置
        output.varying_vec4f[VARYING_COORDS] = _shader_vertexAttrib[index].pos;
        //传入顶点发法向量
        output.varying_vec3f[VARYING_NORMAL] = _shader_vertexAttrib[index].normal;
        
        return pos;
    });
    
    renderer.SetFragmentShader([&](ShaderContext &input)->Vec<4, float>{
        
        Vec<4, float> color;
        
        //根据顶点坐标插值 获取到当前点的uv坐标
        Vec<2, float> vec_uv = input.varying_vec2f[VARYING_TEXUV];
        //使用uv坐标通过插值在纹理上找到uv坐标对应的颜色
        color = _shader_texture->Sample2D(vec_uv[0], vec_uv[1]);
        
        if(_enable_light){
            
            //环境光系数
            Vec<3, float> ka = {0.005, 0.005, 0.005};
            //漫反射系数 b g r
            Vec<3, float> kd = {color[0], color[1], color[2]};
            //镜面反射系数
            Vec<3, float> ks = {0.7937, 0.7937, 0.7937};
            //获取当前点的法向量
            Vec<3, float> normal = input.varying_vec3f[VARYING_NORMAL];
            float p = 150;
            //获取当前点的坐标
            Vec<3, float> pos = {input.varying_vec4f[VARYING_COORDS][0],
                                    input.varying_vec4f[VARYING_COORDS][1],
                                    input.varying_vec4f[VARYING_COORDS][2]};
            //点向光源
            Vec<3, float> vec_light = SubVec(_light_1.pos, pos);
            //点向眼睛
            Vec<3, float> vec_eye = SubVec(_eye_pos, pos);
            //计算光线衰减因子
            float attenuation = DotMutVec(vec_light, vec_light);
            //计算环境光
            Vec<3, float> la = CwiseProduct(amb_light_intensity, ka);
            //计算漫反射 光源强度/衰减系数
            Vec<3, float> ld = CwiseProduct((_light_1.intensity/attenuation), kd);
            //使用法线与光线的偏角修正漫反射
            ld = ld * std::max(0.0f, DotMutVec(Normalize(normal), Normalize(vec_light)));
            //计算镜面反射
            Vec<3, float> h = vec_light + vec_eye;
            h = Normalize(h);
            //镜面反射直射光强度
            Vec<3, float> ls = CwiseProduct((_light_1.intensity/attenuation), kd);
            ls = ls * std::pow(std::max(0.0f, DotMutVec(Normalize(normal), h)), p);
            
            Vec<3, float> light_totle;
            light_totle = light_totle + la;
            light_totle = light_totle + ld;
            light_totle = light_totle + ls;
            //返回对应颜色将被设置到位图对应点上
            color = color + light_totle;
        }
        
        return color;
    });
}

void CubeDrawer::SetCameraPos(const Vec<3, float> &up, const Vec<3, float> &eye, const Vec<3, float> &at){
 
    _eye_pos = eye;
    _camera_mat = ToyCube::CameraMat(up, eye, at);
}

void CubeDrawer::SetPersPro(float fovy, float aspect, float near, float far){
    
    _pers_proj_mat = ToyCube::PersProjMat(fovy, aspect, near, far);
}

void CubeDrawer::RequestRender(const char *path){
    
    //每次绘制前必须清除深度缓存
    renderer.ClearDepthBuffer();
    //清除framebuffer
    renderer.ClearColor(0xff999999);
    
    renderer.DrawOutline(false);
    //计算PV矩阵 p v m
    _mvp_mat = _pers_proj_mat;
    _mvp_mat.RightMut(_camera_mat);
    
    //记录一个默认纹理
    _shader_texture = _texture_2.get();
    //为正方形每个面指定纹理贴图
    LoadTextures();
    
    //设置模型坐标相关
    _cube.SetTransCube(0, 0, -5);
    //开始绘制
    _cube.Draw(renderer, &_shader_texture, &_mvp_mat, _shader_vertexAttrib);
    
    _shader_texture = _texture_2.get();
    
    //renderer.SaveBmp(path);
}

void CubeDrawer::CalculateModelMat(){
    //t r s
}

void CubeDrawer::LoadTextures(){
    
    //为正方形每个面指定纹理贴图
    _cube.SetColor(Cube::SIDE_FRONT, GetCubeColorTexture(TEX_COLOR_BLUE));
    _cube.SetColor(Cube::SIDE_BACK, GetCubeColorTexture(TEX_COLOR_YELLOW));
    _cube.SetColor(Cube::SIDE_LEFT, GetCubeColorTexture(TEX_COLOR_WHITE));
    _cube.SetColor(Cube::SIDE_RIGHT, GetCubeColorTexture(TEX_COLOR_ORANGE));
    _cube.SetColor(Cube::SIDE_TOP, GetCubeColorTexture(TEX_COLOR_RED));
    _cube.SetColor(Cube::SIDE_BOTTON, GetCubeColorTexture(TEX_COLOR_GREEN));
}
